package boot

import (
	"asuOfficialApi/comm"
	"asuOfficialApi/config"
	"asuOfficialApi/web/cron"
	"context"
	"github.com/gorilla/securecookie"
	"github.com/kataras/iris"
	"github.com/kataras/iris/middleware/logger"
	"github.com/kataras/iris/middleware/recover"
	"github.com/kataras/iris/sessions"
	"time"
)

type Configurator func(boot *Bootstrapper)

type Bootstrapper struct {
	*iris.Application
	AppName string

	Sessions *sessions.Sessions
}

func New(appName string, configs ...Configurator) *Bootstrapper {
	b := &Bootstrapper{
		AppName:     appName,
		Application: iris.New(),
	}

	for _, cfg := range configs {
		cfg(b)
	}

	return b
}

func (b *Bootstrapper) SetupSessions(expires time.Duration, cookieHashKey, cookieBlockKey []byte) {
	b.Sessions = sessions.New(sessions.Config{
		Cookie:   "SECRET_SESS_COOKIE_" + b.AppName,
		Expires:  expires,
		Encoding: securecookie.New(cookieHashKey, cookieBlockKey),
	})
}

func (b *Bootstrapper) SetupErrorHandlers() {
	b.OnAnyErrorCode(func(ctx iris.Context) {
		var err iris.Map
		if ctx.GetStatusCode() == iris.StatusNotFound {
			err = comm.Fail(iris.StatusNotFound, "资源不存在")
		} else if ctx.GetStatusCode() == iris.StatusInternalServerError {
			err = comm.Fail(iris.StatusInternalServerError, "服务器内部错误")
		} else {
			err = comm.Fail(ctx.GetStatusCode(), ctx.Values().GetString("message"))
		}
		_, _ = ctx.JSON(err)
	})
}

func (b *Bootstrapper) Configure(cs ...Configurator) {
	for _, c := range cs {
		c(b)
	}
}

// 启动计划任务服务
func (b *Bootstrapper) setupCron() {
	if config.RunningCronService {
		cron.ConfigAppOneCron()
	}
}

func (b *Bootstrapper) Bootstrap() *Bootstrapper {
	b.SetupSessions(24*time.Hour,
		config.CookieHashKey,
		config.CookieBlockKey,
	)
	b.SetupErrorHandlers()

	b.setupCron()

	b.Use(recover.New())
	b.Use(logger.New())

	// 程序中断时处理
	iris.RegisterOnInterrupt(func() {
		timeout := 5 * time.Second
		ctx, cancel := context.WithTimeout(context.Background(), timeout)
		defer cancel()
		//关闭所有主机
		_ = b.Shutdown(ctx)
	})

	return b
}

func (b *Bootstrapper) Listen(addr string, configs ...iris.Configurator) {
	_ = b.Run(iris.Addr(addr), configs...)
}
